﻿/**
 * @file guild_loader.hpp
 * @date 2021/05/12 20:46
 *
 * @author harrybao (harrybao@123u.com)
 *
 * @brief 公会加载
 *
 * @version v1.0.0
 *
 * @copyright Copyright © 2021 All Rights Reserved 上海欢乐互娱网络科技有限公司
 *
 * @par history:
 * <table>
 * <tr><th>Date                     <th>Version     <th>Author <th>Description
 * <tr><td>2021/05/12 20:46         <td>1.0.0       <td>harrybao
 * <td>创建初始版本
 * </table>
 */

// #ifndef GUILD_LOADER_HPP
// #define GUILD_LOADER_HPP

#pragma once

#include <functional>

#include "fwd.h"
#include "guild/guild.h"
#include "guild/guild_redis_key_def.h"
#include "redis/service_redis_fwd.hpp"
#include "util/util.hpp"


namespace guild_service {
namespace detail {

/// 加载所有公会返回结果容器
using LoadAllGuildIdListType = std::vector<guild_id_type>;
/// 加载所有公会回调函数类型
using LoadAllGuildIdCallbackType =
    std::function<void(const LoadAllGuildIdListType &)>;
/// 加载所有公会id字符串类型
using LoadAllGuildIdStrListType =
    std::function<void(const std::vector<std::string> &)>;

/**
 * @brief 同步加载公会Id
 *
 * @param service_name 公会服务名
 * @param guild_id_list 公会id列表
 * @return 加载结果
 * @retval true 加载成功
 * @retval false 加载失败
 */
static bool LoadAllGuildId(const std::string &service_name,
                           LoadAllGuildIdListType &guild_id_list) {
  auto result = redis_command_co(service_name, detail::kQueryGuildIdCommand,
                                 kRedisCommonTimeOut);
  if (!result) {
    LOG_FAIL("redis处理失败 命令:%s 服务名:%s", detail::kQueryGuildIdCommand,
             service_name.c_str());
    return false;
  }

  if (!result->is_success()) {
    LOG_FAIL("redis处理失败 命令:%s 错误:%s 错误码:%u 服务名:%s",
             result->get_command().c_str(), result->get_error().c_str(),
             static_cast<uint32_t>(result->get_error_code()),
             service_name.c_str());
    return false;
  }

  if (redis_reply_is_nil(*result)) {
    LOG_DEBUG("redis获取返回值为nil 命令:%s 服务名:%s",
              result->get_command().c_str(), service_name.c_str());
    return false;
  }

  std::vector<std::string> guild_str_list;
  if (!result->get_return(guild_str_list)) {
    LOG_FAIL("redis获取回复失败 命令:%s 错误:%s 错误码:%d",
             result->get_command().c_str(), result->get_error().c_str(),
             static_cast<int32_t>(result->get_error_code()));
    return false;
  }

  std::vector<std::string> split_str;
  for (const auto &str : guild_str_list) {
    split_str.clear();
    UtilSingleton().splitBy(str, ':', split_str);
    if (split_str.size() >= 2) {
      LOG_DEBUG("获取公会id 键:(%s)", str.c_str());
      guild_id_list.emplace_back(
          static_cast<guild_id_type>(std::stoull(split_str[1])));
    } else {
      LOG_FAIL("字符串分割失败 键:%s", str.c_str());
    }
  }

  LOG_DEBUG("redis同步加载公会id成功 命令:%s 服务名:%s",
            result->get_command().c_str(), service_name.c_str());

  return true;
}

// TODO MT <-> MD _ASSERTE(__acrt_first_block == header);
// https://blog.csdn.net/u010634308/article/details/108241520
// https://www.cnblogs.com/xzabg/p/5875296.html
// https://docs.microsoft.com/en-us/answers/questions/240332/assert-when-using-mtd-dynamic-library.html
static std::vector<std::string> guild_str_list;
/**
 * @brief 异步加载公会Id
 *
 * @param service_name 公会服务名
 * @param callback
 * @return true 加载公会Id成功
 * @return false 加载公会Id失败
 */
static bool LoadAllGuildIdAsync(const std::string &service_name,
                                const LoadAllGuildIdStrListType &callback) {
  if (!callback) {
    return false;
  }

  if (!redis_command_async(
          service_name, detail::kQueryGuildIdCommand, kRedisCommonTimeOutAsync,
          [callback](const redis_result_type &result, std::uint64_t) {
            if (!result.is_success()) {
              LOG_FAIL("redis处理失败 命令:%s 错误:%s 错误码:%d",
                       result.get_command().c_str(), result.get_error().c_str(),
                       static_cast<int32_t>(result.get_error_code()));
              return;
            }
            if (redis_reply_is_nil(result)) {
              LOG_DEBUG("redis回复为nil 命令:%s 错误:%s 错误码:%d",
                        result.get_command().c_str(),
                        result.get_error().c_str(),
                        static_cast<int32_t>(result.get_error_code()));
              return;
            }
            {
              guild_str_list.clear();
              if (!result.get_return(guild_str_list)) {
                LOG_FAIL("redis获取回复失败 命令:%s 错误:%s 错误码:%d",
                         result.get_command().c_str(),
                         result.get_error().c_str(),
                         static_cast<int32_t>(result.get_error_code()));
                return;
              }
              callback(guild_str_list);
            }
          },
          0)) {
    LOG_FAIL("redis执行失败 命令:%s 服务名:%s", detail::kQueryGuildIdCommand,
             service_name.c_str());
    return false;
  }

  // LOG_DEBUG("redis异步加载公会id成功 命令:%s 服务名:%s",
  // kQueryGuildIdCommand, service_name.c_str());

  return true;
}

/**
 * @brief 同步递增公会常用id
 *
 * @tparam IntType 返回值整型类型
 * @param service_name 公会服务名
 * @param redis_key_name
 * @param value 递增结束后的值
 * @return true 递增成功
 * @return false 递增失败
 */
template <typename IntType>
static bool IncrGuildGeneralId(const std::string &service_name,
                               const std::string &redis_key_name,
                               IntType &value) {
  value = 0;

  std::stringstream ss;
  ss << "INCR " << redis_key_name;
  auto result = redis_command_co(service_name, ss.str(), kRedisCommonTimeOut);
  if (!result) {
    LOG_FAIL("redis处理失败 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }

  if (!result->is_success()) {
    LOG_FAIL("redis处理失败 命令:%s 错误:%s 错误码:%u 服务名:%s",
             result->get_command().c_str(), result->get_error().c_str(),
             static_cast<uint32_t>(result->get_error_code()),
             service_name.c_str());
    return false;
  }

  std::size_t ret_val;
  if (!result->get_return(ret_val)) {
    LOG_FAIL("redis获取返回值失败 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }

  value = static_cast<std::size_t>(ret_val);

  LOG_DEBUG("redis同步加载公会id成功 公会id:%llu 命令:%s 服务名:%s", value,
            result->get_command().c_str(), service_name.c_str());

  return true;
}

/**
 * @brief 同步根据角色唯一id获取公会id
 *
 * @param service_name 公会服务名
 * @param role_uuid 角色唯一id
 * @param guild_id  公会id
 * @return true 获取成功
 * @return false 获取失败
 */
static bool LoadGuildIdByRole(const std::string &service_name,
                              const role_uuid_type role_uuid,
                              guild_id_type &guild_id) {
  guild_id = kInvalidGuildId;

  std::stringstream ss;
  ss << kRedisGetOp << detail::kLoadGuildIdByRoleKeyPrefix << role_uuid;

  auto result = redis_command_co(service_name, ss.str(), kRedisCommonTimeOut);
  if (!result) {
    LOG_FAIL("redis处理失败 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }
  if (!result->is_success()) {
    LOG_FAIL("redis处理失败 命令:%s 错误:%s 错误码:%u 服务名:%s",
             result->get_command().c_str(), result->get_error().c_str(),
             static_cast<uint32_t>(result->get_error_code()),
             service_name.c_str());
    return false;
  }

  if (redis_reply_is_nil(*result)) {
    LOG_DEBUG("redis返回为nil 命令:(%s) 服务名:%s",
              result->get_command().c_str(), service_name.c_str());
    return false;
  }

  std::string guild_id_str;
  if (!result->get_return(guild_id_str)) {
    LOG_FAIL("redis获取返回值失败 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }

  if (guild_id_str.empty()) {
    LOG_FAIL("redis获取返回值为空 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }

  if (!UtilSingleton()->isnumber(guild_id_str)) {
    LOG_FAIL("redis返回值不是数字 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }

  guild_id = std::stoull(guild_id_str);

  return true;
}

/**
 * @brief 加载角色唯一id
 *
 * @param service_name
 * @param account
 * @param passwd
 * @param role_uuid
 * @return true
 * @return false
 */
static bool LoadRoleUuid(const std::string &service_name,
                         const std::string &account, const std::string &passwd,
                         role_uuid_type &role_uuid) {
  role_uuid = kInvalidRoleUuid;

  std::stringstream ss;
  ss << kRedisGetOp << detail::kAccountKeyPrefix << account << ":" << passwd;

  auto result = redis_command_co(service_name, ss.str(), kRedisCommonTimeOut);
  if (!result) {
    LOG_FAIL("redis处理失败 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }
  if (!result->is_success()) {
    LOG_FAIL("redis处理失败 命令:%s 错误:%s 错误码:%u 服务名:%s",
             result->get_command().c_str(), result->get_error().c_str(),
             static_cast<uint32_t>(result->get_error_code()),
             service_name.c_str());
    return false;
  }

  if (redis_reply_is_nil(*result)) {
    LOG_DEBUG("redis返回为nil 命令:(%s) 服务名:%s",
              result->get_command().c_str(), service_name.c_str());
    return false;
  }

  std::string role_uuid_str;
  if (!result->get_return(role_uuid_str)) {
    LOG_FAIL("redis获取返回值失败 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }

  if (role_uuid_str.empty()) {
    LOG_FAIL("redis获取返回值为空 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }

  if (!UtilSingleton()->isnumber(role_uuid_str)) {
    LOG_FAIL("redis返回值不是数字 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }

  role_uuid = std::stoull(role_uuid_str);

  return true;
}

/**
 * @brief 加载角色唯一id
 *
 * @param service_name 公会服务名
 * @param token 凭证
 * @param role_uuid 角色唯一id
 * @return true 加载成功
 * @return false 加载失败
 */
static bool LoadRoleUuid(const std::string &service_name,
                         const token_type token, role_uuid_type &role_uuid) {
  role_uuid = kInvalidRoleUuid;

  std::stringstream ss;
  ss << kRedisGetOp << detail::kTokenKeyPrefix << token;

  auto result = redis_command_co(service_name, ss.str(), kRedisCommonTimeOut);
  if (!result) {
    LOG_FAIL("redis处理失败 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }
  if (!result->is_success()) {
    LOG_FAIL("redis处理失败 命令:%s 错误:%s 错误码:%u 服务名:%s",
             result->get_command().c_str(), result->get_error().c_str(),
             static_cast<uint32_t>(result->get_error_code()),
             service_name.c_str());
    return false;
  }

  if (redis_reply_is_nil(*result)) {
    LOG_DEBUG("redis返回为nil 命令:(%s) 服务名:%s",
              result->get_command().c_str(), service_name.c_str());
    return false;
  }

  std::string role_uuid_str;
  if (!result->get_return(role_uuid_str)) {
    LOG_FAIL("redis获取返回值失败 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }

  if (role_uuid_str.empty()) {
    LOG_FAIL("redis获取返回值为空 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }

  if (!UtilSingleton()->isnumber(role_uuid_str)) {
    LOG_FAIL("redis返回值不是数字 命令:%s 服务名:%s", ss.str().c_str(),
             service_name.c_str());
    return false;
  }

  role_uuid = std::stoull(role_uuid_str);

  return true;
}

}  // namespace detail
}  // namespace guild_service

// #endif // GUILD_LOADER_HPP